#
# 状态机

from abc import abstractmethod
import time, random

from .logger import logger

from .actions import \
    adb_stop, adb_action_wait, adb_action_tap, adb_action_swipe, \
    adb_action_find_img, adb_action_until_find_img


POS_CENTER = (640, 360)

POS_B_TIMES_FINAL = (450, 120)
POS_B_TIMES_CURRENT = (200, 120)

POS_APPLE = (430, 70)

POS_BUTTON_YES = (770, 420)
POS_BUTTON_YES_NO_TITLE = (780, 290)
# 地图子菜单位置
POS_MAP_COMING2 = (950, 250)

POS_COMBAT_HEAD1 = (100, 650)
POS_COMBAT_HEAD2 = (270, 650)
POS_COMBAT_HEAD3 = (440, 650)
POS_COMBAT_HEAD4 = (610, 650)
POS_COMBAT_HEAD5 = (800, 650)
POS_COMBAT_HEAD6 = (970, 650)

POS_COMBAT_SKILL0 = (150, 540)
POS_COMBAT_SKILL1 = (400, 540)
POS_COMBAT_SKILL2 = (640, 540)
POS_COMBAT_SKILL3 = (890, 540)
POS_COMBAT_SUB = (1130, 540)

POS_COMBAT_ATTACK = (1170, 620)

COMBAT_COUNT = 0

# combat count
def combat_count():
    global COMBAT_COUNT
    COMBAT_COUNT = COMBAT_COUNT + 1

def combat_count_reset():
    global COMBAT_COUNT
    COMBAT_COUNT = 0


APP_NAME = ""


#----------------------------------------------------------------------
# state 基类
class GameState():

    # 由于检测代价比较大，此处需要一个预估的延迟时间（秒），减少检测开销
    _done_delay = 3

    def __init__(self):
        self._next_state = None
        self._next_state1 = None
        self._next_state2 = None
        self._next_state3 = None
        self._done_timestamp = 0

    def switch(self):
        if self._next_state2 and self._next_state != self._next_state2:
            self._next_state = self._next_state2

    def switch3(self):
        if not self._next_state3:
            logger.error('self._next_state3 is None. ')
            return
        if self._next_state != self._next_state3:
            self._next_state = self._next_state3

    def reset(self):
        self._next_state = self._next_state1

    def set_next_state1(self, state):
        self._next_state1 = state
        self._next_state = state

    def set_next_state2(self, state):
        self._next_state2 = state

    def set_next_state3(self, state):
        self._next_state3 = state

    def done(self, tnow: float):
        if tnow < self._done_timestamp:
            # 时间未到，继续等待
            return False
        else:
            return self._done()

    def _done(self):
        return True

    def enter(self, switch: bool = True):
        if switch:
            logger.info(f'{self.__class__.__name__} enter >>>>>>>>>>')
        self._done_timestamp = time.time() + self._done_delay
        # 进入前先 reset 一下
        self.reset()
        self._enter()

    @abstractmethod
    def _enter(self):
        pass


#----------------------------------------------------------------------
# 初始状态
class InitState(GameState):

    _done_delay = 8

    def _done(self):
        return True

    def _enter(self):
        # 查找公告关闭按钮
        res = adb_action_find_img('./data/aed_button_tips_close.png')
        if res:
            adb_action_tap(res)
            adb_action_wait(5)
        else:
            adb_action_wait(2)


init_state = InitState()


#----------------------------------------------------------------------
# 补给状态
class SupplyState(GameState):

    _done_delay = 25

    def _done(self):
        # only check the time
        return True

    def _enter(self):
        # 找到地图按钮
        adb_action_find_img_click('./data/aed_button_map.png')
        adb_action_wait(4)
        # 点击？？？
        adb_action_tap(POS_B_TIMES_FINAL)
        adb_action_wait(2)
        # 找到次元
        adb_action_find_img_click('./data/aed_map_button_ciyuan.png', 0.15)
        adb_action_wait(1)
        # yes
        adb_action_tap(POS_BUTTON_YES)
        adb_action_wait(6)
        # hotel
        adb_action_tap(POS_APPLE)
        adb_action_wait(2)
        adb_action_tap(POS_CENTER)
        adb_action_wait(2)
        # yes
        adb_action_tap(POS_BUTTON_YES)
        adb_action_wait(4)
        # tap
        adb_action_tap(POS_CENTER)
        adb_action_wait(3)


supply_state = SupplyState()


#----------------------------------------------------------------------
# 自来也
class ToComingState(GameState):

    _done_delay = 15

    def _done(self):
        return True

    def _enter(self):
        # 找到地图按钮
        adb_action_find_img_click('./data/aed_button_map.png')
        adb_action_wait(4)
        # 现代
        adb_action_tap(POS_B_TIMES_CURRENT)
        adb_action_wait(2)
        # 找到自来也
        adb_action_find_img_click('./data/aed_map_button_coming.png', 0.15)
        adb_action_wait(1)
        # 二级菜单
        adb_action_tap(POS_MAP_COMING2)
        adb_action_wait(1)
        # yes
        adb_action_tap(POS_BUTTON_YES)
        adb_action_wait(5)


to_coming_state = ToComingState()


LAST_DIRECTION = 0

#----------------------------------------------------------------------
def change_direction():
    global LAST_DIRECTION
    if LAST_DIRECTION == 0:
        LAST_DIRECTION = 1
    else:
        LAST_DIRECTION = 0

#----------------------------------------------------------------------
# 巡逻状态
class PatrolState(GameState):

    _done_delay = 3
    _combat_img_filename = "./data/aed_combat.png"

    def _done(self):
        return True

    def _enter(self):
        global LAST_DIRECTION
        if LAST_DIRECTION == 1:
            if self.right():
                return
            self.left()
        else:
            if self.left():
                return
            self.right()

    def left(self):
        adb_action_swipe((960, 300), (320, 300), 3000)
        if adb_action_find_img(self._combat_img_filename, crop = True):
            self.switch()
            change_direction()
            return True

    def right(self):
        adb_action_swipe((320, 300), (960, 300), 3000)
        if adb_action_find_img(self._combat_img_filename, crop = True):
            self.switch()
            change_direction()
            return True


patrol_state = PatrolState()


#----------------------------------------------------------------------
# 战斗状态
class CombatState(GameState):

    _done_delay = 15

    def _done(self):
        return True

    def _enter(self):
        combat_count()
        self.check_supply()
        adb_action_tap(POS_COMBAT_HEAD1)
        adb_action_wait(0.5)
        adb_action_tap(POS_COMBAT_SKILL2)
        adb_action_wait(0.5)
        adb_action_tap(POS_COMBAT_HEAD3)
        adb_action_wait(0.5)
        adb_action_tap(POS_COMBAT_SUB)
        adb_action_wait(0.5)
        adb_action_tap(POS_COMBAT_HEAD5)
        adb_action_wait(0.5)
        adb_action_tap(POS_COMBAT_HEAD4)
        adb_action_wait(0.5)
        adb_action_tap(POS_COMBAT_SUB)
        adb_action_wait(0.5)
        adb_action_tap(POS_COMBAT_HEAD6)
        adb_action_wait(0.5)
        adb_action_tap(POS_COMBAT_ATTACK)
        adb_action_wait(3)
        adb_action_click_until_find_img('./data/aed_button_map.png', 0.1,
                                        POS_COMBAT_ATTACK, 3)

    def check_supply(self):
        if adb_action_find_img("./data/aed_empty_mana.png", 0.15, False):
            logger.info(f"combat state: -EMPTY MANA-, for {COMBAT_COUNT} combats. ")
            combat_count_reset()
            self.switch()
        else:
            logger.info(f"combat state: ok, for {COMBAT_COUNT} combats. ")

combat_state = CombatState()



# 默认的后续状态
patrol_state.set_next_state1(patrol_state)
patrol_state.set_next_state2(combat_state)
combat_state.set_next_state1(patrol_state)
combat_state.set_next_state2(supply_state)
supply_state.set_next_state1(to_coming_state)
init_state.set_next_state1(to_coming_state)
to_coming_state.set_next_state1(patrol_state)


#----------------------------------------------------------------------
# state 管理器
class StateManager():

    current_state_timestamp = 0
    _app_name = None

    def __init__(self, app_name: str):
        self._init_state = None
        self._current_state = None
        self._patrol_state = None
        self._app_name = app_name

    def init(self, state: GameState, patrol: GameState):
        self._init_state = state
        self._current_state = state
        self._patrol_state = patrol

    def enter(self, imm: bool = False, delay: int = 1):
        if imm:
            self._current_state = self._patrol_state
        self.current_state_timestamp = time.time()
        self._current_state.enter()
        self.loop(delay)

    def loop(self, delay: int = 1):
        tnow = time.time()
        if self._current_state.done(tnow):
            switch = False
            if self._current_state != self._current_state._next_state:
                self._current_state = self._current_state._next_state
                switch = True
                self.current_state_timestamp = tnow
            self._current_state.enter(switch)
        last_sc = tnow - self.current_state_timestamp
        if last_sc > 180:
            # 在一个状态停留的时间过长, 重置到初始状态
            logger.warn(f'{self._current_state} last {last_sc} seconds, reset. ')
            adb_stop(self._app_name)
            adb_action_wait(3)
            self.enter(False, delay)
        else:
            time.sleep(delay)
            self.loop(delay)


state_mgr = StateManager(APP_NAME)
state_mgr.init(init_state, patrol_state)
